using Engine;
using Engine.Graphics;
using Game;

namespace SCIENEW {
    public class SixDirectionModelDevice: DefaultDevice {
        public BlockMesh m_standaloneBlockMesh = new();

        public BlockMesh[] m_blockMeshesByFace = new BlockMesh[6];

        public BoundingBox[][] m_collisionBoxesByFace = new BoundingBox[6][];

        public bool m_faceTransparent;

        public SixDirectionModelDevice(string id, string modelPath, string meshName, bool faceTransparent = false) : base(id) {
            Model model = ContentManager.Get<Model>(modelPath);
            Matrix boneAbsoluteTransform = BlockMesh.GetBoneAbsoluteTransform(model.FindMesh(meshName).ParentBone);
            for (int i = 0; i < 6; i++)
            {
                Matrix matrix = (i >= 4) ? ((i != 4) ? (Matrix.CreateRotationX((float)Math.PI) * Matrix.CreateTranslation(0.5f, 1f, 0.5f)) : Matrix.CreateTranslation(0.5f, 0f, 0.5f)) : (Matrix.CreateRotationX((float)Math.PI / 2f) * Matrix.CreateTranslation(0f, 0f, -0.5f) * Matrix.CreateRotationY((float)i * (float)Math.PI / 2f) * Matrix.CreateTranslation(0.5f, 0.5f, 0.5f));
                m_blockMeshesByFace[i] = new BlockMesh();
                m_blockMeshesByFace[i].AppendModelMeshPart(model.FindMesh(meshName).MeshParts[0], boneAbsoluteTransform * matrix, makeEmissive: false, flipWindingOrder: false, doubleSided: false, flipNormals: false, Color.White);
                m_collisionBoxesByFace[i] = [m_blockMeshesByFace[i].CalculateBoundingBox()];
            }
            m_standaloneBlockMesh.AppendModelMeshPart(model.FindMesh(meshName).MeshParts[0], boneAbsoluteTransform * Matrix.CreateTranslation(0f, -0.5f, 0f), makeEmissive: false, flipWindingOrder: false, doubleSided: false, flipNormals: false, Color.White);
            this.m_faceTransparent = faceTransparent;
        }

        public override bool IsFaceTransparent(SubsystemTerrain subsystemTerrain, int face, int value) => m_faceTransparent;

        protected virtual int GetDirection(int value) => GetDirection_Static(value);

        public static int GetDirection_Static(int value) => DevicesUtils.GetInnerData(value);

        public override void GenerateTerrainVertices(BlockGeometryGenerator generator, TerrainGeometry geometry, int value, int x, int y, int z) {
            generator.GenerateShadedMeshVertices(
                BlocksManager.Blocks[BaseDeviceBlock.Index],
                x,
                y,
                z,
                m_blockMeshesByFace[GetDirection(value)],
                Color.White,
                null,
                null,
                geometry.GetGeometry(IndustrialModLoader.IETexture).SubsetAlphaTest
            );
        }

        public override void DrawBlock(PrimitivesRenderer3D primitivesRenderer, int value, Color color, float size, ref Matrix matrix, DrawBlockEnvironmentData environmentData) {
            BlocksManager.DrawMeshBlock(
                primitivesRenderer,
                m_standaloneBlockMesh,
                IndustrialModLoader.IETexture,
                color,
                size,
                ref matrix,
                environmentData
            );
        }

        public override BlockPlacementData GetPlacementValue(SubsystemTerrain subsystemTerrain, ComponentMiner componentMiner, int value, TerrainRaycastResult raycastResult) {
            return new BlockPlacementData() { CellFace = raycastResult.CellFace, Value = DevicesBlockManager.GetDeviceValue(Id, DevicesUtils.GetDirectionXYZ(componentMiner)) };
        }

        public override void GetDropValues(SubsystemTerrain subsystemTerrain, int oldValue, int newValue, int toolLevel, List<BlockDropValue> dropValues, out bool showDebris) {
            showDebris = true;
            dropValues.Add(new BlockDropValue { Value = DevicesBlockManager.GetDeviceValue(Id, 0), Count = 1 });
        }

        public override int GetFaceTextureSlot(int face, int value) => 105;
    }
}